import requests
import json
import os
import random
import ctypes
import datetime
import glob
from win10toast import ToastNotifier

CONFIG_FILE = "config.json"
WALLPAPER_HISTORY = "history.json"

def load_config():
    """加载配置文件并验证必需字段"""
    if not os.path.exists(CONFIG_FILE):
        raise FileNotFoundError("配置文件不存在")
    
    with open(CONFIG_FILE, "r") as f:
        config = json.load(f)
    
    required_keys = ["api_key", "categories", "save_dir", "min_width", "min_height", "max_limit"]
    for key in required_keys:
        if key not in config:
            raise ValueError(f"配置文件中缺少必要字段: {key}")
        
    # 验证数值型参数
    try:
        config["min_width"] = int(config["min_width"])
        config["min_height"] = int(config["min_height"])
        config["max_limit"] = int(config["max_limit"])
    except ValueError:
        raise ValueError("长宽参数和最大限制必须为整数")
    
    return config

def ensure_directory(path):
    """确保保存目录存在"""
    os.makedirs(path, exist_ok=True)

def get_photo_history():
    """读取历史记录"""
    if not os.path.exists(WALLPAPER_HISTORY):
        return []
    try:
        with open(WALLPAPER_HISTORY, "r") as f:
            return json.load(f)
    except (json.JSONDecodeError, FileNotFoundError):
        return []

def update_photo_history(photo_id, max_limit, save_dir):
    """更新历史记录并处理旧文件"""
    history = get_photo_history()
    
    # 添加新记录
    new_entry = {
        "id": photo_id,
        "time": datetime.datetime.now().isoformat()
    }
    history.append(new_entry)
    
    # 删除超过限制的旧记录
    while len(history) > max_limit:
        oldest = history.pop(0)
        # 删除对应的图片文件
        for file_path in glob.glob(os.path.join(save_dir, f"{oldest['id']}.*")):
            try:
                os.remove(file_path)
            except Exception as e:
                print(f"删除旧文件失败: {str(e)}")
    
    # 保存更新后的历史记录
    with open(WALLPAPER_HISTORY, "w") as f:
        json.dump(history, f, indent=2)

def fetch_random_photo(api_key, categories, min_width, min_height):
    """获取符合尺寸要求的随机图片"""
    query = random.choice(categories)
    page = random.randint(1, 50)
    per_page = 15
    
    url = f"https://api.pexels.com/v1/search?query={query}&page={page}&per_page={per_page}"
    
    headers = {"Authorization": api_key}
    try:
        response = requests.get(url, headers=headers, timeout=15)
        response.raise_for_status()
        data = response.json()
        
        if not data.get("photos"):
            raise ValueError("未找到符合条件的图片")
        
        # 筛选符合尺寸要求的图片
        valid_photos = [
            photo for photo in data["photos"]
            if photo["width"] >= min_width 
            and photo["height"] >= min_height
        ]
        
        if not valid_photos:
            raise ValueError("当前搜索没有符合尺寸要求的图片")
        
        selected = random.choice(valid_photos)
        return selected["src"]["original"], selected["id"]
    
    except requests.exceptions.RequestException as e:
        raise ConnectionError(f"API请求失败: {str(e)}")

def download_image(url, save_dir, photo_id):
    """下载图片到指定目录"""
    try:
        response = requests.get(url, stream=True, timeout=15)
        response.raise_for_status()
        
        # 获取文件扩展名
        ext = url.split(".")[-1].split("?")[0]
        filename = f"{photo_id}.{ext}"
        save_path = os.path.join(save_dir, filename)
        
        with open(save_path, "wb") as f:
            for chunk in response.iter_content(1024):
                f.write(chunk)
        
        return save_path
    except Exception as e:
        if 'save_path' in locals() and os.path.exists(save_path):
            os.remove(save_path)
        raise IOError(f"图片下载失败: {str(e)}")

def set_windows_wallpaper(image_path):
    """设置Windows壁纸"""
    if not os.path.exists(image_path):
        raise FileNotFoundError("壁纸文件不存在")
    
    # 转换为Windows风格路径
    image_path = os.path.abspath(image_path).replace("/", "\\")
    SPI_SETDESKWALLPAPER = 0x0014
    ctypes.windll.user32.SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, image_path, 3)

def show_notification(title, message):
    """显示Windows通知"""
    try:
        ToastNotifier().show_toast(title, message, duration=10)
    except Exception:
        print(f"{title}: {message}")

def main():
    try:
        # 加载配置
        config = load_config()
        api_key = config["api_key"]
        categories = config["categories"]
        save_dir = config["save_dir"]
        min_width = config["min_width"]
        min_height = config["min_height"]
        max_limit = config["max_limit"]
        
        # 初始化环境
        ensure_directory(save_dir)
        history = get_photo_history()
        history_ids = {entry["id"] for entry in history}
        
        # 获取新图片（最多重试5次）
        max_retries = 5
        for attempt in range(max_retries):
            try:
                photo_url, photo_id = fetch_random_photo(api_key, categories, min_width, min_height)
                
                if photo_id not in history_ids:
                    break
                
                print(f"找到重复图片，正在重试... ({attempt+1}/{max_retries})")
            except Exception as e:
                if attempt == max_retries - 1:
                    raise
                print(f"获取失败，正在重试... ({attempt+1}/{max_retries})")
        else:
            raise ValueError("多次尝试后仍未找到符合要求的新图片")
        
        # 下载并设置壁纸
        save_path = download_image(photo_url, save_dir, photo_id)
        set_windows_wallpaper(save_path)
        update_photo_history(photo_id, max_limit, save_dir)
        
        show_notification("壁纸更新成功", f"新壁纸已设置: {os.path.basename(save_path)}")
        
    except Exception as e:
        show_notification("壁纸更新失败", str(e))

if __name__ == "__main__":
    main()